/*
 * \brief  Delivery and reception of asynchronous notifications
 * \author Norman Feske
 * \date   2008-09-05
 *
 * Each transmitter sends signals to one fixed destination.
 * A receiver can receive signals from multiple sources.
 */

/*
 * Copyright (C) 2008-2009 Norman Feske
 * Genode Labs, Feske & Helmuth Systementwicklung GbR
 *
 * This file is part of the Genode OS framework, which is distributed
 * under the terms of the GNU General Public License version 2.
 */

#ifndef _INCLUDE__BASE__SIGNAL_H__
#define _INCLUDE__BASE__SIGNAL_H__

#include <base/native_signal.h>

namespace Genode {

	/**
	 * Capability type for signal receiver
	 */
	typedef Native_signal_receiver_capability Signal_receiver_capability;


	/**
	 * Signal
	 *
	 * A signal represents a number of asynchronous notifications produced by
	 * one transmitter. If notifications are generated at a higher rate than as
	 * they can be processed at the receiver, the transmitter counts the
	 * notifications and delivers the total amount with the next signal
	 * transmission. This way, the total number of notifications gets properly
	 * communicated to the receiver even if the receiver is not highly
	 * responsive.
	 *
	 * Asynchronous notifications do not carry any payload because this payload
	 * would have to be queued at the transmitter. However, each transmitter
	 * imprints a receiver-capability protected payload into each signal. This
	 * argument can be used by the receiver to distinguish signals coming from
	 * different transmitters.
	 */
	class Signal : Native_signal
	{
		private:

			friend class Signal_receiver;
			Signal(Native_signal native_signal) : Native_signal(native_signal) { }

		public:

			/**
			 * Return imprinted notification argument
			 */
			long imprint() { return Native_signal::imprint(); }

			/**
			 * Return number of signals received from the same transmitter
			 */
			int  num() { return Native_signal::num(); }
	};


	/**
	 * Signal transmitter
	 *
	 * Each signal-transmitter instance acts on behalf the receiver specified
	 * as constructor argument. Therefore, the resources needed for the
	 * transmitter such as the consumed memory 'sizeof(Signal_transmitter)'
	 * should be accounted to the corresponding receiver.
	 */
	class Signal_transmitter : Native_signal_transmitter
	{
		public:

			/**
			 * Constructor
			 *
			 * \param receiver  capability to signal receiver
			 */
			Signal_transmitter(Signal_receiver_capability receiver = Signal_receiver_capability())
			: Native_signal_transmitter(receiver) { }

			/**
			 * Set signal receiver
			 */
			void receiver(Signal_receiver_capability receiver) {
				Native_signal_transmitter::receiver(receiver); }

			/**
			 * Trigger signal submission to receiver
			 */
			void submit() { return Native_signal_transmitter::submit(); }
	};


	/**
	 * Signal receiver
	 */
	class Signal_receiver : Native_signal_receiver
	{
		public:

			/**
			 * Constructor
			 *
			 * \param cap_session  CAP session for allocating signal-receiver capabilities
			 */
			Signal_receiver(Cap_session *cap_session) : Native_signal_receiver(cap_session) { }

			/**
			 * Return new signal-receiver capability
			 *
			 * \param imprint  argument to be delivered with each signal
			 * \return         new signal-receiver capability that can be
			 *                 passed to a signal transmitter
			 */
			Signal_receiver_capability cap(long imprint = 0) {
				return Native_signal_receiver::cap(imprint); }

			/**
			 * Return true if signal was received
			 */
			bool pending() { return Native_signal_receiver::pending(); }

			/**
			 * Block until a signal is received
			 *
			 * \return received signal
			 */
			Signal wait_for_signal() { return Signal(Native_signal_receiver::wait_for_signal()); }
	};
}

#endif /* _INCLUDE__BASE__SIGNAL_H__ */
